package com.aps.common.service;

import com.aps.common.entity.ApsCode;
import com.aps.common.mapper.ApsCodeMapper;
import com.aps.common.redis.RedisUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * APS 码值管理服务
 * 
 * 功能说明：
 * 1. 提供码值的增删改查功能
 * 2. 支持分页查询和按类型查询
 * 3. 集成Redis缓存，提升查询性能
 * 4. 缓存按租户隔离，有效期2小时
 * 
 * @Author nbZhuozh
 * @Date 2025-11-21  16:31
 **/
@Service
@Slf4j
public class ApsCodeService extends TestGenericService {

    @Resource
    private ApsCodeMapper apsCodeMapper;

    /**
     * 缓存键前缀
     */
    private static final String CACHE_PREFIX = "aps:code:";
    
    /**
     * 缓存时长：2小时
     */
    private static final Duration CACHE_DURATION = Duration.ofHours(2);

    static {
        log.info("ApsCodeService 初始化，启用Redis缓存管理");
    }

    /**
     * 获取租户级别的缓存键（所有码值列表）
     */
    private String getTenantAllCacheKey(String tenantId) {
        return CACHE_PREFIX + tenantId + ":all";
    }

    /**
     * 获取按类型分类的缓存键
     */
    private String getTenantTypeCacheKey(String tenantId, String codeType) {
        return CACHE_PREFIX + tenantId + ":type:" + codeType;
    }

    /**
     * 分页查询当前租户下所有码值
     * 优先从缓存读取，缓存未命中则查询数据库并缓存
     * 
     * @param pageNum  页码
     * @param pageSize 每页大小
     * @return 分页结果
     */
    public Page<ApsCode> selectPageByTenantId(int pageNum, int pageSize) {
        String tenantId = getCurrentTenantId();
        log.debug("分页查询租户 {} 的码值列表，页码：{}，大小：{}", tenantId, pageNum, pageSize);
        // 构建查询条件
        LambdaQueryWrapper<ApsCode> queryWrapper = Wrappers.lambdaQuery(ApsCode.class)
                .eq(ApsCode::getTenantId, tenantId)
                .orderByAsc(ApsCode::getCodeType)
                .orderByAsc(ApsCode::getSort)
                .orderByAsc(ApsCode::getCodeValue);
        // 分页查询
        Page<ApsCode> page = new Page<>(pageNum, pageSize);
        Page<ApsCode> result = apsCodeMapper.selectPage(page, queryWrapper);
        log.info("查询租户 {} 的码值列表完成，共 {} 条记录", tenantId, result.getTotal());
        return result;
    }

    /**
     * 查询当前租户下所有码值（不分页）
     * 优先从缓存读取
     * 
     * @return 所有码值列表
     */
    public List<ApsCode> selectAllByTenantId() {
        String tenantId = getCurrentTenantId();
        String cacheKey = getTenantAllCacheKey(tenantId);
        // 1. 先查缓存
        List<ApsCode> cachedList = RedisUtils.getCacheObject(cacheKey);
        if (cachedList != null && !cachedList.isEmpty()) {
            log.debug("从缓存获取租户 {} 的所有码值，命中缓存", tenantId);
            return cachedList;
        }
        // 2. 缓存未命中，查询数据库
        log.debug("缓存未命中，从数据库查询租户 {} 的所有码值", tenantId);
        LambdaQueryWrapper<ApsCode> queryWrapper = Wrappers.lambdaQuery(ApsCode.class)
                .eq(ApsCode::getTenantId, tenantId)
                .eq(ApsCode::getStatus, 1)  // 只查询启用状态的
                .orderByAsc(ApsCode::getCodeType)
                .orderByAsc(ApsCode::getSort)
                .orderByAsc(ApsCode::getCodeValue);
        List<ApsCode> list = apsCodeMapper.selectList(queryWrapper);
        // 3. 缓存结果
        if (list != null && !list.isEmpty()) {
            RedisUtils.setCacheObject(cacheKey, list, CACHE_DURATION);
            log.info("已缓存租户 {} 的码值列表，共 {} 条，缓存时长 {} 小时", tenantId, list.size(), CACHE_DURATION.toHours());
        }
        return list;
    }


    public ApsCode selectByCodeValue(String codeValue , String codeType){
        if(StringUtils.isBlank(codeValue) || StringUtils.isBlank(codeType)){
            return null;
        }
        List<ApsCode> apsCodes = selectByCodeType(codeType);
        return apsCodes
                .stream()
                .filter(i -> StringUtils.equals(codeValue, i.getCodeValue()))
                .findFirst()
                .orElse(null);
    }



    /**
     * 根据码表类型查询租户下的码值列表
     * 优先从缓存读取
     * 
     * @param codeType 码表类型（如：USER_STATUS、ORDER_TYPE）
     * @return 指定类型的码值列表
     */
    public List<ApsCode> selectByCodeType(String codeType) {
        if (StringUtils.isBlank(codeType)) {
            log.warn("码表类型参数为空，无法查询");
            return Collections.emptyList();
        }
        String tenantId = getCurrentTenantId();
        String cacheKey = getTenantTypeCacheKey(tenantId, codeType);
        // 1. 先查缓存
        List<ApsCode> cachedList = RedisUtils.getCacheObject(cacheKey);
        if (cachedList != null) {
            log.debug("从缓存获取租户 {} 的码表类型 {} 的码值，命中缓存", tenantId, codeType);
            return cachedList;
        }
        // 2. 缓存未命中，查询数据库
        log.debug("缓存未命中，从数据库查询租户 {} 的码表类型 {}", tenantId, codeType);
        LambdaQueryWrapper<ApsCode> queryWrapper = Wrappers.lambdaQuery(ApsCode.class)
                .eq(ApsCode::getTenantId, tenantId)  // 租户ID过滤
                .eq(ApsCode::getCodeType, codeType)
                .eq(ApsCode::getStatus, 1)  // 只查询启用状态的
                .orderByAsc(ApsCode::getSort)
                .orderByAsc(ApsCode::getCodeValue);

        List<ApsCode> list = apsCodeMapper.selectList(queryWrapper);
        // 3. 缓存结果（即使为空也缓存，避免缓存穿透）
        RedisUtils.setCacheObject(cacheKey, list, CACHE_DURATION);
        log.info("已缓存租户 {} 的码表类型 {} 的码值列表，共 {} 条", tenantId, codeType, list.size());

        return list;
    }

    /**
     * 新增码值
     * 新增后清除相关缓存
     * 
     * @param apsCode 码值对象
     * @return 是否新增成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean insert(ApsCode apsCode) {
        if (apsCode == null) {
            log.warn("新增码值失败：参数为空");
            return false;
        }
        // 设置租户ID和基础字段
        String tenantId = getCurrentTenantId();
        String userId = getCurrentUserId();
        LocalDateTime now = LocalDateTime.now();
        // 注意：ApsCode继承自ExtMap，ExtMap继承自BaseEntity
        // BaseEntity中的字段需要设置
        apsCode.setId(null);  // 让 MyBatis Plus 自动生成ID
        apsCode.setTenantId(tenantId);  // 设置租户ID
        apsCode.setCreateTime(now);
        apsCode.setUpdateTime(now);
        apsCode.setCreateBy(userId);
        apsCode.setUpdateBy(userId);
        // 参数校验
        if (StringUtils.isBlank(apsCode.getCodeType()) || StringUtils.isBlank(apsCode.getCodeValue())) {
            log.warn("新增码值失败：codeType 或 codeValue 为空");
            return false;
        }
        // 检查是否已存在相同的 codeType + codeValue
        LambdaQueryWrapper<ApsCode> checkWrapper = Wrappers.lambdaQuery(ApsCode.class)
                .eq(ApsCode::getTenantId, tenantId)
                .eq(ApsCode::getCodeType, apsCode.getCodeType())
                .eq(ApsCode::getCodeValue, apsCode.getCodeValue());
        Long count = apsCodeMapper.selectCount(checkWrapper);
        if (count != null && count > 0) {
            log.warn("新增码值失败：租户 {} 中已存在 codeType={}, codeValue={} 的记录", 
                     tenantId, apsCode.getCodeType(), apsCode.getCodeValue());
            return false;
        }
        // 插入数据库
        int result = apsCodeMapper.insert(apsCode);
        boolean success = result > 0;
        if (success) {
            // 清除相关缓存
            clearCache(tenantId, apsCode.getCodeType());
            log.info("新增码值成功：ID={}, codeType={}, codeValue={}, 租户={}", 
                     apsCode.getId(), apsCode.getCodeType(), apsCode.getCodeValue(), tenantId);
        } else {
            log.error("新增码值失败：codeType={}, codeValue={}, 租户={}", 
                      apsCode.getCodeType(), apsCode.getCodeValue(), tenantId);
        }
        return success;
    }

    /**
     * 修改码值
     * 修改后清除相关缓存
     * 
     * @param apsCode 码值对象（必须包含ID）
     * @return 是否修改成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean update(ApsCode apsCode) {
        if (apsCode == null || StringUtils.isBlank(apsCode.getId())) {
            log.warn("修改码值失败：参数为空或ID为空");
            return false;
        }

        String tenantId = getCurrentTenantId();
        String userId = getCurrentUserId();

        // 先查询原记录，用于清除缓存
        ApsCode oldCode = apsCodeMapper.selectById(apsCode.getId());
        if (oldCode == null) {
            log.warn("修改码值失败：ID={} 的记录不存在", apsCode.getId());
            return false;
        }

        // 更新基础字段
        apsCode.setUpdateTime(LocalDateTime.now());
        apsCode.setUpdateBy(userId);
        // 不允许修改以下字段
        apsCode.setCreateTime(oldCode.getCreateTime());
        apsCode.setCreateBy(oldCode.getCreateBy());

        // 如果修改了 codeType 或 codeValue，需要检查是否重复
        if (!oldCode.getCodeType().equals(apsCode.getCodeType()) 
            || !oldCode.getCodeValue().equals(apsCode.getCodeValue())) {
            
            LambdaQueryWrapper<ApsCode> checkWrapper = Wrappers.lambdaQuery(ApsCode.class)
                    .eq(ApsCode::getTenantId, tenantId)
                    .eq(ApsCode::getCodeType, apsCode.getCodeType())
                    .eq(ApsCode::getCodeValue, apsCode.getCodeValue())
                    .ne(ApsCode::getId, apsCode.getId());
            
            Long count = apsCodeMapper.selectCount(checkWrapper);
            if (count != null && count > 0) {
                log.warn("修改码值失败：租户 {} 中已存在 codeType={}, codeValue={} 的其他记录", 
                         tenantId, apsCode.getCodeType(), apsCode.getCodeValue());
                return false;
            }
        }

        // 更新数据库
        int result = apsCodeMapper.updateById(apsCode);
        boolean success = result > 0;

        if (success) {
            // 清除相关缓存（包括旧的和新的 codeType）
            clearCache(tenantId, oldCode.getCodeType());
            if (!oldCode.getCodeType().equals(apsCode.getCodeType())) {
                clearCache(tenantId, apsCode.getCodeType());
            }
            log.info("修改码值成功：ID={}, codeType={}, codeValue={}, 租户={}", 
                     apsCode.getId(), apsCode.getCodeType(), apsCode.getCodeValue(), tenantId);
        } else {
            log.error("修改码值失败：ID={}, 租户={}", apsCode.getId(), tenantId);
        }

        return success;
    }

    /**
     * 删除码值
     * 删除后清除相关缓存
     * 
     * @param id 码值ID
     * @return 是否删除成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(String id) {
        if (StringUtils.isBlank(id)) {
            log.warn("删除码值失败：ID为空");
            return false;
        }

        String tenantId = getCurrentTenantId();

        // 先查询记录
        ApsCode apsCode = apsCodeMapper.selectById(id);
        if (apsCode == null) {
            log.warn("删除码值失败：ID={} 的记录不存在", id);
            return false;
        }

        // 检查是否为系统内置
        if (apsCode.getIsSystem() != null && apsCode.getIsSystem() == 1) {
            log.warn("删除码值失败：ID={} 为系统内置码值，不允许删除", id);
            return false;
        }

        // 执行删除（逻辑删除）
        int result = apsCodeMapper.deleteById(id);
        boolean success = result > 0;

        if (success) {
            // 清除相关缓存
            clearCache(tenantId, apsCode.getCodeType());
            log.info("删除码值成功：ID={}, codeType={}, codeValue={}, 租户={}", 
                     id, apsCode.getCodeType(), apsCode.getCodeValue(), tenantId);
        } else {
            log.error("删除码值失败：ID={}, 租户={}", id, tenantId);
        }

        return success;
    }

    /**
     * 批量删除码值
     * 
     * @param ids 码值ID列表
     * @return 是否删除成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean batchDelete(List<String> ids) {
        if (ids == null || ids.isEmpty()) {
            log.warn("批量删除码值失败：ID列表为空");
            return false;
        }

        String tenantId = getCurrentTenantId();
        
        // 查询要删除的记录
        List<ApsCode> toDeleteList = apsCodeMapper.selectBatchIds(ids);
        
        // 检查是否有系统内置的
        boolean hasSystemCode = toDeleteList.stream()
                .anyMatch(code -> code.getIsSystem() != null && code.getIsSystem() == 1);
        
        if (hasSystemCode) {
            log.warn("批量删除码值失败：包含系统内置码值，不允许删除");
            return false;
        }

        // 执行批量删除
        int result = apsCodeMapper.deleteBatchIds(ids);
        boolean success = result > 0;

        if (success) {
            // 清除所有相关缓存
            toDeleteList.stream()
                    .map(ApsCode::getCodeType)
                    .distinct()
                    .forEach(codeType -> clearCache(tenantId, codeType));
            
            log.info("批量删除码值成功：删除 {} 条记录，租户={}", result, tenantId);
        } else {
            log.error("批量删除码值失败：租户={}", tenantId);
        }

        return success;
    }

    /**
     * 根据ID查询码值
     * 
     * @param id 码值ID
     * @return 码值对象
     */
    public ApsCode selectById(String id) {
        if (StringUtils.isBlank(id)) {
            log.warn("查询码值失败：ID为空");
            return null;
        }

        ApsCode apsCode = apsCodeMapper.selectById(id);
        log.debug("根据ID查询码值：ID={}, 结果={}", id, apsCode != null ? "找到" : "未找到");
        return apsCode;
    }

    /**
     * 清除指定租户和类型的缓存
     * 
     * @param tenantId 租户ID
     * @param codeType 码表类型
     */
    private void clearCache(String tenantId, String codeType) {
        try {
            // 清除全部码值缓存
            String allCacheKey = getTenantAllCacheKey(tenantId);
            RedisUtils.deleteObject(allCacheKey);
            log.debug("清除缓存：{}", allCacheKey);

            // 清除特定类型的缓存
            if (StringUtils.isNotBlank(codeType)) {
                String typeCacheKey = getTenantTypeCacheKey(tenantId, codeType);
                RedisUtils.deleteObject(typeCacheKey);
                log.debug("清除缓存：{}", typeCacheKey);
            }
        } catch (Exception e) {
            log.error("清除缓存失败：tenantId={}, codeType={}", tenantId, codeType, e);
        }
    }

    /**
     * 清除当前租户的所有缓存
     * 可用于刷新缓存
     */
    public void clearAllCache() {
        String tenantId = getCurrentTenantId();
        try {
            // 注意：这里需要根据实际的Redis工具类方法来实现模糊删除
            // 如果 RedisUtils 不支持模糊删除，则需要逐个删除
            log.info("清除租户 {} 的所有码值缓存", tenantId);
            
            // 至少清除全部码值缓存
            String allCacheKey = getTenantAllCacheKey(tenantId);
            RedisUtils.deleteObject(allCacheKey);
        } catch (Exception e) {
            log.error("清除租户 {} 的所有缓存失败", tenantId, e);
        }
    }
}
